;
(function (window, angular) {
    'use strict';

    function isAllowI18n(scopeF) {
        // 判断当前页面是否允许国际化
        scopeF.multiLan = scopeF.$root.allowI18n;
    }

    angular.module("Directive.All", ["Directive.Selector", "Directive.Validation"])
        // 控件、元素
        .directive('ybCheckBox', ["$timeout", function ($timeout) {
            return {
                restrict: 'A',
                templateUrl: 'js/directive/tpl/checkTemplate.html',
                replace: true,
                scope: {
                    ybChecked: '=',
                    ybClick: '&',
                    ybDisabled: '=',
                    ybCheckName: '@'
                },
                link: function (scope, element, attrs) {

                    isAllowI18n(scope);

                    scope.customWidth = attrs.customWidth;
                    if (angular.isUndefined(scope.ybChecked)) {
                        scope.ybChecked = false;
                    }
                    scope.toggleIcon = function () {
                        if (scope.ybDisabled == true) {
                            return;
                        }
                        if (scope.ybChecked == "notAll") {
                            scope.ybChecked = true;
                        } else {
                            scope.ybChecked = !scope.ybChecked;
                        }
                        $timeout(function () {
                            scope.ybClick();
                        });
                    };
                }
            }
        }])

        .directive('ybTableDrag', ["$timeout", "$filter", function ($timeout, $filter) {
            return {
                restrict: 'A',
                scope: {
                    ybWidth: '=',
                    ybIndex: '=',
                    ybData: '='
                },
                link: function (scope, element, attrs) {
                    var totalWidth = 0;
                    var minWidth = 20;
                    var preWidth = 0;
                    var thisWidth = 0;
                    var endPreWidth = '';
                    var endCurrentWidth = '';
                    var prev = angular.element(element.parent()[0].previousElementSibling);
                    element[0].onmousedown = function ($event) {
                        totalWidth = $filter('convertCMToPx')(scope.ybWidth);
                        var e = $event || window.event;
                        var disX = e.clientX;
                        preWidth = prev.css('width');
                        thisWidth = element.parent().css('width');
                        cacleUom();
                        document.onmousemove = function ($event) {
                            var ev = $event || window.event;
                            var moveDistance = ev.clientX - disX;
                            var currPreWidth = 0;
                            var currThisWidth = 0;
                            if (moveDistance >= 0) {
                                var disWidth = thisWidth - moveDistance;
                                if (disWidth <= minWidth) {
                                    currThisWidth = minWidth;
                                    disWidth = thisWidth - minWidth >= 0 ? thisWidth - minWidth : 0;
                                    currPreWidth = preWidth + disWidth;
                                } else {
                                    currThisWidth = thisWidth - moveDistance;
                                    currPreWidth = preWidth + moveDistance;
                                }
                            } else {
                                moveDistance = -moveDistance;
                                var disWidth = preWidth - moveDistance;
                                if (disWidth <= minWidth) {
                                    disWidth = preWidth - minWidth >= 0 ? preWidth - minWidth : 0;
                                    currPreWidth = minWidth;
                                    currThisWidth = thisWidth + disWidth;
                                } else {
                                    currThisWidth = thisWidth + moveDistance;
                                    currPreWidth = preWidth - moveDistance;
                                }
                            }
                            endPreWidth = Math.round(currPreWidth / totalWidth * 100) + '%';
                            endCurrentWidth = Math.round(currThisWidth / totalWidth * 100) + '%';
                            prev.css({
                                'width': endPreWidth
                            });
                            element.parent().css({
                                'width': endCurrentWidth
                            });
                        };
                        document.onmouseup = function () {
                            document.onmousemove = null;
                            document.onmouseup = null;
                            angular.forEach(scope.ybData, function (item, index) {
                                if (index == scope.ybIndex - 1) {
                                    item.colWidth = endPreWidth;
                                }
                                if (index == scope.ybIndex) {
                                    item.colWidth = endCurrentWidth;
                                }
                            })
                        };
                    };

                    function cacleUom() {
                        if (preWidth.indexOf('%') != -1) {
                            preWidth = Number(preWidth.substring(0, preWidth.length - 1)) / 100 * totalWidth;
                        } else {
                            preWidth = Number(preWidth.split('px')[0]);
                        }
                        if (thisWidth.indexOf('%') != -1) {
                            thisWidth = Number(thisWidth.substring(0, thisWidth.length - 1)) / 100 * totalWidth;
                        } else {
                            thisWidth = Number(thisWidth.split('px')[0]);
                        }
                    }
                }
            }
        }])

        .directive('ybRadio', ["$timeout", function ($timeout) {
            return {
                require: '?ngModel',
                restrict: 'A',
                replace: true,
                scope: {
                    ybValue: '=',
                    ybClick: '&',
                    ybRadioName: '@',
                    ybDisabled: "=ybDisabled",
                    delaySetVal: "=",
                    changeTop: "@"
                },
                templateUrl: 'js/directive/tpl/radioTemplate.html',
                link: function (scope, element, attrs, ctrl) {
                    var value = scope.$eval(attrs.value) || attrs.value;
                    scope.radioValue = "";
                    isAllowI18n(scope)
                    if (angular.isObject(value)) {
                        scope.valueIsObj = true;
                    } else {
                        scope.valueIsObj = false;
                    }
                    if (angular.isDefined(value)) {
                        scope.radioValue = value;
                    }
                    if (angular.isDefined(scope.ybValue)) {
                        scope.radioValue = scope.ybValue.id;
                    }

                    scope.changeIcon = function () {
                        if (!!scope.ybDisabled) {
                            return;
                        }
                        if (!!scope.delaySetVal) {
                            scope.ybClick();

                            $timeout(function () {
                                ctrl.$setViewValue(scope.radioValue);
                            });

                        } else {
                            ctrl.$setViewValue(scope.radioValue);

                            $timeout(function () {
                                scope.ybClick();
                            });
                        }
                    };

                    scope.$watch(function () {
                        return ctrl.$modelValue;
                    }, function () {
                        scope.modelValue = ctrl.$modelValue;
                    });
                }
            }
        }])

        .directive("ybCrumbs", ['$translate', '$rootScope', '$state', 'EventBus', function ($translate, $rootScope, $state, EventBus) {
            return {
                restrict: "A",
                replace: "true",
                scope: {
                    isEdit: '='
                },
                template: "<span>" +
                    "<i class='yb-icon ico-address m-r-xs font-12'></i>{{crumbs}}" +
                    "</span>",
                link: function (scope, element, attrs, ctrl) {
                    isAllowI18n(scope);

                    scope.crumbs = "";
                    var curStateName = $state.current.name;
                    var menuItem = $rootScope.primaryMenuItem;

                    function setCrumbs() {
                        if (!menuItem) {
                            return;
                        }
                        scope.crumbs = menuItem.name && scope.multiLan ? $translate.instant(menuItem.name) : menuItem.name;
                        angular.forEach(menuItem.children, function (item) {
                            if (item.leaf === 1 && item.state === curStateName) {
                                var itemName = item.name && scope.multiLan ? $translate.instant(item.name) : item.name;
                                scope.crumbs += " > " + itemName;
                                return false;
                            }
                            if (item.leaf === 0) {
                                angular.forEach(item.children, function (subItem) {
                                    if (subItem.state === curStateName) {
                                        var itemName = item.name && scope.multiLan ? $translate.instant(item.name) : item.name;
                                        var subItemName = subItem.name && scope.multiLan ? $translate.instant(subItem.name) : subItem.name;
                                        scope.crumbs += " > " + itemName + " > " + (scope.isEdit ? subItem.name.replace('新增', '编辑') : subItemName);
                                        return false;
                                    }
                                });
                            }
                        });
                    }

                    EventBus.Subscribe("setCrumbsItem", setCrumbsItem);

                    function setCrumbsItem(data) {
                        menuItem = data;
                        setCrumbs();
                    }

                    scope.$on("$destroy", function () {
                        EventBus.Unsubscribe("setCrumbsItem", setCrumbsItem);
                    });

                    setCrumbs();
                }
            }
        }])

        .directive("ybPageInfo", function () {
            return {
                restrict: "A",
                replace: true,
                scope: {
                    pageInfo: "=ngModel",
                    pageSizeOptions: "=", // 指定每页可以显示多少条
                    ybRefresh: "&"
                },
                templateUrl: "js/directive/tpl/pageInfo.html",
                controller: 'PageInfoCtrl'
            };
        })
        .controller("PageInfoCtrl", ["$scope", "$attrs", function ($scope) {

            isAllowI18n($scope);

            $scope.targetPage = "1";
            $scope.maxPages = 5;

            $scope.pageSizeList = [10, 20, 30, 40, 50, 100, 200];
            
            if (angular.isDefined($scope.pageInfo.pageSizeList) && $scope.pageInfo.pageSizeList.length > 0) {
                $scope.pageSizeList = $scope.pageInfo.pageSizeList;
            }

            if (angular.isDefined($scope.pageSizeOptions)) { // 没有用以前的配置：$scope.pageInfo.pageSizeList
                $scope.pageSizeList = $scope.pageSizeOptions;
            }

            if (!!$scope.pageInfo && !!$scope.pageInfo.hidePageNo) {
                $scope.maxPages = 0;
            }

            $scope.changePageSize = function () {
                $scope.pageInfo.curPage = 1;
                $scope.ybRefresh();
            };

            $scope.pageChange = function () {
                $scope.ybRefresh();
            };

            $scope.pageJump = function (targetPage) {
                $scope.targetPage = targetPage.replace(/\b(0+)/gi, "");
                var totalPages = $scope.pageInfo.totalPages;
                var regPage = /^\d+$/;
                if ($scope.targetPage < 1 || !regPage.test($scope.targetPage)) {
                    $scope.targetPage = 1;
                }
                if ($scope.targetPage > totalPages) {
                    $scope.targetPage = totalPages;
                }
                $scope.pageInfo.curPage = $scope.targetPage;
                $scope.ybRefresh();
            };
        }])

        .directive('ngScrollbar', [
            function () {
                return {
                    restrict: 'AE',
                    transclude: true,
                    scope: {
                        scrollbarConfig: '=scrollbarConfig',
                        scrollbarX: '@', // the value is true or false, to configure the x scrollbar create or no create.
                        scrollbarY: '@' // the value is true or false, to configure the y scrollbar create or no create.
                    },
                    template: '<div style="position:relative;width:100%;height:100%;">\
                                    <div class="ngscroll-content-container" style="display:inline-block;width:100%;margin-top:0;margin-left:0" ng-transclude>\
                                    </div>\
                                    <ng-scrollbar-x ng-if="scrollbarX || scrollbarX === undefined"></ng-scrollbar-x>\
                                    <ng-scrollbar-y ng-if="scrollbarY || scrollbarY === undefined"></ng-scrollbar-y>\
                                </div>',
                    controller: 'scrollbarController',
                    compile: function (element) {
                        if (window.navigator.userAgent.indexOf("MSIE 8.0") == -1) {
                            element.css('overflow', 'hidden');
                            return function (scope, element, attrs, ctrl) {
                                ctrl.init(element, scope.scrollbarConfig);
                            };
                        } else {
                            element.css('overflow', 'auto');
                            return;
                        }
                    }
                };
            }
        ])
        .controller('scrollbarController', [function () {
            var defaultConfig = {
                dragSpeed: 1, //default browser delta value is 120 or -120
                autoResize: false, // if need auto resize, default false
                show: false, // if need show when mouse not enter the container element which need scrollbar, default false.
                scrollbar: {
                    width: 6, //scrollbar width
                    hoverWidth: 8, //scrollbar width when the mouse hover on it
                    color: 'rgba(0,0,0,1)' //scrollbar background color
                },
                scrollbarContainer: {
                    width: 12, //scrollbarContainer width
                    color: 'rgba(0,0,0,1)' // scrollbarContainer background
                }
            };
            var containerElement, // the element which need the directive of ngscrollbar
                contentElement, // the element which transclude the true content
                config, // config
                scrollbarMargin, // the variable is used to descide the scrollbar element top or left to its parent element scrollbarContainer
                scrollbarHoverMargin; // the variable is used to descide the scrollbar element top or left to its parent element scrollbarContainer when the mouse hover on the scrollbar

            /**
             * it must be called before the controller is used.
             * @param  {jqlite object} element         it's necessary variable
             * @param  {object} scrollbarConfig        the config which is defined by user
             * @return
             */
            this.init = function (element, scrollbarConfig) {
                containerElement = element;
                config = angular.copy(angular.extend(defaultConfig, scrollbarConfig || {}));
                contentElement = angular.element(element[0].querySelector('.ngscroll-content-container'));
                scrollbarMargin = (config.scrollbarContainer.width - config.scrollbar.width) / 2;
                scrollbarHoverMargin = (config.scrollbarContainer.width - config.scrollbar.hoverWidth) / 2;
            };

            angular.extend(this, {
                /**
                 * Wrap window in an angular jqLite object.
                 */
                winEl: angular.element(window),
                /**
                 * get the element which need the directive of ngscrollbar
                 * @return {jqlite object}
                 */
                getContainerElement: function () {
                    return containerElement;
                },
                /**
                 * the element which transclude the true content
                 * @return {jqlite object}
                 */
                getContentElement: function () {
                    return contentElement;
                },
                /**
                 * get the config
                 * @return {object}
                 */
                getConfig: function () {
                    return config;
                },
                /**
                 * get the scrollbarMargin
                 * @return {number}
                 */
                getScrollbarMargin: function () {
                    return scrollbarMargin;
                },
                /**
                 * get the scrollbarHoverMargin
                 * @return {number}
                 */
                getScrollbarHoverMargin: function () {
                    return scrollbarHoverMargin;
                }
            });
        }])

        .directive('ngScrollbarY', ['$timeout', function ($timeout) {
            return {
                restrict: 'AE',
                require: '^ngScrollbar',
                replace: true,
                template: '<div class="ngscrollbar-container-y" ng-style="styles.scrollbarContainer"><div class="ngscrollbar-y" ng-style="styles.scrollbar"></div></div>',
                compile: function () {
                    return function (scope, element, attrs, ctrl) {

                        var config = ctrl.getConfig(),
                            docEl = angular.element(document),
                            containerElement = ctrl.getContainerElement(),
                            contentElement = ctrl.getContentElement(),
                            scrollbar = angular.element(element[0].querySelector('.ngscrollbar-y')),
                            scrollbarMargin = ctrl.getScrollbarMargin(),
                            scrollbarHoverMargin = ctrl.getScrollbarHoverMargin();

                        scope.styles = {
                            scrollbarContainer: {
                                position: 'absolute',
                                width: config.scrollbarContainer.width + 'px',
                                height: '100%',
                                top: 0,
                                right: '-1px',
                                background: config.scrollbarContainer.color,
                                // 'border-radius': config.scrollbarContainer.width / 2 + 'px'
                                'border-radius': '0px'
                            },
                            scrollbar: {
                                position: 'absolute',
                                width: config.scrollbar.width + 'px',
                                right: scrollbarMargin + 'px',
                                cursor: 'default',
                                opacity: 0,
                                transition: 'opacity .3s ease-in-out, border-radius .1s linear, width .1s linear, right .1s linear',
                                background: config.scrollbar.color,
                                'border-radius': config.scrollbar.width / 2 + 'px'
                                // 'border-radius': '0px'
                            }
                        };

                        var getContentHeight = function () {
                            return contentElement[0].offsetHeight;
                        };

                        var getContainerHeight = function () {
                            return containerElement[0].offsetHeight;
                        };

                        var getScrollbarHeight = function () {
                            var height = Math.pow(getContainerHeight(), 2) / getContentHeight() - scrollbarMargin * 2;
                            return height;
                        };

                        var isOverflow = function () {
                            return getContentHeight() > getContainerHeight();
                        };

                        var hideScrollbar = function () {
                            scrollbar.css('opacity', 0);
                        };

                        var showScrollbar = function () {
                            scrollbar.css('opacity', 1);
                        };

                        var reset = function () {
                            var oldMarginTop = parseInt(contentElement.css('margin-top'), 10);
                            contentElement.css('margin-top', '0px'); // this is for the element which has the attribute of max-height
                            if (isOverflow()) {
                                element.css('display', 'block');
                                scrollbar.css('height', getScrollbarHeight() + 'px');
                                scrollTo(oldMarginTop);
                                if (config.show) {
                                    showScrollbar();
                                }
                            } else {
                                element.css('display', 'none');
                            }
                        };

                        var scrollTo = function (top) {
                            top = Math.min(0, Math.max(top, getContainerHeight() - getContentHeight()));
                            contentElement.css('margin-top', top + 'px');
                            scrollbar.css('top', -top / getContentHeight() * getContainerHeight() + scrollbarMargin + 'px');
                        };

                        var scroll = function (distance) {
                            var newTop = parseInt(contentElement.css('margin-top'), 10) + distance;
                            scrollTo(newTop);
                        };

                        containerElement.on('mousewheel', function (event) {
                            if (!isOverflow()) {
                                return;
                            }
                            event.preventDefault();
                            if (event.originalEvent !== undefined) {
                                event = event.originalEvent;
                            }
                            scroll(event.wheelDeltaY || event.wheelDelta);
                        });

                        if (window.navigator.userAgent.toLowerCase().indexOf('firefox') >= 0) {
                            containerElement.on('wheel', function (event) {
                                if (!isOverflow()) {
                                    return;
                                }
                                event.preventDefault();
                                if (event.originalEvent !== undefined) {
                                    event = event.originalEvent;
                                }
                                scroll(-event.deltaY * 40); // the ff delta value is 3 or -3 when scroll and the chrome or ie is -120 or 120, so it must multiply by 40
                            });
                        }

                        element.on('mouseenter', function () {
                            // element.css('background', config.scrollbarContainer.color);
                            scrollbar.css('width', config.scrollbar.hoverWidth + 'px');
                            scrollbar.css('right', scrollbarHoverMargin + 'px');
                            // scrollbar.css('border-radius', config.scrollbar.hoverWidth / 2 + 'px');
                        });

                        element.on('mouseleave', function () {
                            // element.css('background', 'none');
                            scrollbar.css('width', config.scrollbar.width + 'px');
                            scrollbar.css('right', scrollbarMargin + 'px');
                            // scrollbar.css('border-radius', config.scrollbar.width / 2 + 'px');
                        });

                        var scrollbarMousedown = false,
                            axisY,
                            mouseInElement = false;

                        if (!config.show) {
                            containerElement.on('mouseenter', function () {
                                mouseInElement = true;
                                showScrollbar();
                            });
                            containerElement.on('mouseleave', function () {
                                mouseInElement = false;
                                if (scrollbarMousedown) {
                                    return;
                                }
                                hideScrollbar();
                            });
                        }

                        scrollbar.on('mousedown', function (event) {
                            event.preventDefault();
                            axisY = event.screenY;
                            scrollbarMousedown = true;
                            docEl.one('mouseup', function () {
                                scrollbarMousedown = false;
                                if (!config.show && !mouseInElement) {
                                    hideScrollbar();
                                }
                                // docEl.off('mouseup', arguments.callee);
                            });
                        });
                        docEl.on('mousemove', function (event) {
                            if (scrollbarMousedown) {
                                event.preventDefault();
                                scroll(-(event.screenY - axisY) * config.dragSpeed * getContentHeight() / getContainerHeight());
                                axisY = event.screenY;
                            }
                        });

                        $timeout(function () {
                            reset();
                            if (!!document.createStyleSheet) { //if the browser is ie browser
                                contentElement.on('DOMNodeInserted', reset);
                                contentElement.on('DOMNodeRemoved', reset);
                            } else {
                                var observer = new MutationObserver(function (mutations) {
                                    if (mutations.length) {
                                        reset();
                                    }
                                });
                                observer.observe(contentElement[0], {
                                    childList: true,
                                    subtree: true
                                });
                            }
                        }, 5);

                        // Redraw the scrollbar when window size changes.
                        if (config.autoResize) {
                            // Closure to guard against leaking variables.
                            (function () {
                                var redrawTimer;

                                ctrl.winEl.on('resize', function (e) {
                                    if (redrawTimer) {
                                        clearTimeout(redrawTimer);
                                    }
                                    redrawTimer = setTimeout(function () {
                                        redrawTimer = null;
                                        reset();
                                    }, 50);
                                });
                            })();
                        }
                    };
                }
            };
        }])

        .directive('ngScrollbarX', ['$timeout', function ($timeout) {
            return {
                restrict: 'AE',
                replace: true,
                require: '^ngScrollbar',
                template: '<div class="ngscrollbar-container-x" ng-style="styles.scrollbarContainer"><div class="ngscrollbar-x" ng-style="styles.scrollbar"></div></div>',
                compile: function () {
                    return function (scope, element, attrs, ctrl) {

                        var config = ctrl.getConfig(),
                            docEl = angular.element(document),
                            containerElement = ctrl.getContainerElement(),
                            containerDom = containerElement[0],
                            contentElement = ctrl.getContentElement(), //the container of content
                            scrollbar = angular.element(element[0].querySelector('.ngscrollbar-x')),
                            scrollbarMargin = ctrl.getScrollbarMargin(),
                            scrollbarHoverMargin = ctrl.getScrollbarHoverMargin();

                        scope.styles = {
                            scrollbarContainer: {
                                position: 'absolute',
                                width: '100%',
                                transition: 'background .3s ease-in-out',
                                'border-radius': config.scrollbarContainer.width / 2 + 'px'
                            },
                            scrollbar: {
                                position: 'absolute',
                                cursor: 'default',
                                opacity: 0,
                                transition: 'opacity .3s ease-in-out, border-radius .1s linear, width .1s linear, right .1s linear',
                                background: config.scrollbar.color,
                                'border-radius': config.scrollbar.width / 2 + 'px'
                            }
                        };

                        element.css('height', config.scrollbarContainer.width + 'px'); // set the scrollbarContainer height;
                        element.css('bottom', 0); // set scrollbarContainer top
                        element.css('left', 0); //set scrollbarContainer left
                        scrollbar.css('top', scrollbarMargin + 'px'); //set scrollbar top
                        scrollbar.css('height', config.scrollbar.width + 'px');

                        var getContentWidth = function () {
                            return contentElement[0].scrollWidth;
                        };

                        var getContainerWidth = function () {
                            return containerDom.offsetWidth;
                        };

                        var getScrollbarWidth = function () {
                            return Math.pow(getContainerWidth(), 2) / getContentWidth() - scrollbarMargin * 2;
                        };

                        var showScrollbar = function () {
                            scrollbar.css('opacity', 1);
                        };

                        var hideScrollbar = function () {
                            scrollbar.css('opacity', 0);
                        };

                        var isOverflow = function () {
                            return getContentWidth() > getContainerWidth();
                        };

                        var reset = function () {
                            var oldMarginLeft = parseInt(contentElement.css('margin-left'), 10);
                            contentElement.css('margin-left', '0px');
                            if (isOverflow()) {
                                element.css('display', 'block');
                                scrollbar.css('width', getScrollbarWidth() + 'px');
                                scrollTo(oldMarginLeft);
                                if (config.show) {
                                    showScrollbar();
                                }
                            } else {
                                element.css('display', 'none');
                            }
                        };

                        var scrollTo = function (left) {
                            left = Math.min(0, Math.max(left, getContainerWidth() - getContentWidth()));
                            contentElement.css('margin-left', left + 'px');
                            scrollbar.css('left', -left / getContentWidth() * getContainerWidth() + scrollbarMargin + 'px');
                        };

                        var scroll = function (distance) {
                            var left = parseInt(contentElement.css('margin-left'), 10) + distance;
                            scrollTo(left);
                        };

                        element.on('mouseenter', function () {
                            element.css('background', config.scrollbarContainer.color);
                            scrollbar.css('height', config.scrollbar.hoverWidth + 'px');
                            scrollbar.css('top', scrollbarHoverMargin + 'px');
                            scrollbar.css('border-radius', config.scrollbar.hoverWidth / 2 + 'px');
                        });

                        element.on('mouseleave', function () {
                            element.css('background', 'none');
                            scrollbar.css('height', config.scrollbar.width + 'px');
                            scrollbar.css('top', scrollbarMargin + 'px');
                            scrollbar.css('border-radius', config.scrollbar.width / 2 + 'px');
                        });

                        var scrollbarMousedown = false,
                            axisX,
                            mouseInElement = false;

                        if (!config.show) {
                            containerElement.on('mouseenter', function () {
                                mouseInElement = true;
                                showScrollbar();
                            });
                            containerElement.on('mouseleave', function () {
                                mouseInElement = false;
                                if (scrollbarMousedown) {
                                    return;
                                }
                                hideScrollbar();
                            });
                        }

                        scrollbar.on('mousedown', function (event) {
                            event.preventDefault();
                            scrollbarMousedown = true;
                            axisX = event.screenX;
                            docEl.one('mouseup', function () {
                                scrollbarMousedown = false;
                                if (!config.show && !mouseInElement) {
                                    hideScrollbar();
                                }
                                // docEl.off('mouseup', arguments.callee);
                            });
                        });
                        docEl.on('mousemove', function (event) {
                            if (scrollbarMousedown) {
                                event.preventDefault();
                                scroll(-(event.screenX - axisX) * config.dragSpeed * getContentWidth() / getContainerWidth());
                                axisX = event.screenX;
                            }
                        });

                        $timeout(function () {
                            reset();
                            if (!!document.createStyleSheet) { //if the browser is ie browser
                                contentElement.on('DOMNodeInserted', reset);
                                contentElement.on('DOMNodeRemoved', reset);
                            } else {
                                var observer = new MutationObserver(function (mutations) {
                                    if (mutations.length) {
                                        reset();
                                    }
                                });
                                observer.observe(contentElement[0], {
                                    childList: true,
                                    subtree: true
                                });
                            }
                        }, 5);

                        // Redraw the scrollbar when window size changes.
                        if (config.autoResize) {
                            // Closure to guard against leaking variables.
                            (function () {
                                var redrawTimer;

                                ctrl.winEl.on('resize', function (e) {
                                    if (redrawTimer) {
                                        clearTimeout(redrawTimer);
                                    }
                                    redrawTimer = setTimeout(function () {
                                        redrawTimer = null;
                                        reset();
                                    }, 50);
                                });
                            })();
                        }
                    };
                }
            };
        }])

        .directive('ybStepBar', ["$timeout", function () {
            return {
                restrict: 'A',
                replace: true,
                scope: {
                    stepData: '=?ngModel'
                },
                templateUrl: 'js/directive/tpl/stepBar.html',
                link: function (scope, element, attrs, ctrl) {
                    scope.stepWidth = {
                        width: 100 / (scope.stepData.list.length - 1) + "%"
                    };
                }
            }
        }])

        .directive('ybShuttleBox', ["$timeout", function () {
            return {
                restrict: 'A',
                replace: true,
                scope: {
                    shuttleConf: '=?ngModel',
                    selectedData: "=?selectedData",
                    callBack: "&",
                },
                templateUrl: 'js/directive/tpl/shuttleBox.html',
                controller: 'ShuttleBoxCtrl'
            }
        }])
        .controller('ShuttleBoxCtrl', ["$scope", "ybWidget", "ybHttp", "MESG_TYPE", function ($scope, ybWidget, ybHttp, MESG_TYPE) {
            $scope.markInfo = {
                allChecked: false
            };
            $scope.pageInfo = {
                totalPages: 1,
                totalRows: 0,
                pageSize: 10,
                curPage: 1
            };
            $scope.leftTbConf = $scope.shuttleConf.leftTbConf;
            $scope.leftDataConf = $scope.shuttleConf.leftDataConf;
            $scope.condition = {};
            $scope.leftData = [];

            function getLeftData(curPage) {
                var service = $scope.leftDataConf.service;
                var reqUrl = $scope.leftDataConf.reqUrl;
                var param = {};
                if (!!$scope.leftDataConf.page) {
                    param.pageSize = $scope.pageInfo.pageSize;
                    if (!!curPage) {
                        $scope.pageInfo.curPage = curPage;
                    }
                    param.pageNum = $scope.pageInfo.curPage;
                }
                param.filters = angular.copy(angular.extend($scope.condition, $scope.leftDataConf.otherParams));
                ybHttp[$scope.leftDataConf.reqType](service, reqUrl, param).then(function (resp) {
                    if (resp.code !== 0) {
                        ybWidget.ShowMessage(resp, MESG_TYPE.Error);
                        return;
                    }
                    angular.forEach(resp.value.list, function (item) {
                        item.isChecked = item.isSelected === 1;
                    });
                    if (!!$scope.leftDataConf.page) {
                        $scope.pageInfo.totalRows = resp.value.total;
                        $scope.pageInfo.totalPages = resp.value.pages;
                    }
                    $scope.leftData = resp.value.list;
                    $scope.markInfo.allChecked = checkAll();
                });
            }

            $scope.search = function (curPage) {
                getLeftData(curPage);
            };

            $scope.selectAll = function () {
                for (var i = 0, len = $scope.leftData.length; i < len; i++) {
                    $scope.leftData[i].isChecked = $scope.markInfo.allChecked;
                }
                var param = {
                    removeList: [],
                    dealerList: []
                };
                angular.forEach($scope.leftData, function (item) {
                    handleSaveOrRemoveData(param, item);
                });
                saveOrRemove(param);
            };

            function checkAll() {
                var selectAll = false;
                for (var i = 0, len = $scope.leftData.length; i < len; i++) {
                    if (!$scope.leftData[i].isChecked) {
                        selectAll = false;
                        break;
                    }
                    selectAll = true;
                }
                return selectAll;
            }

            function handleSaveOrRemoveData(param, item) {
                if (item.isChecked && (!item.dealerActiveId&&!item.userDealerId)) {
                    param.dealerList.push(item);
                }
                if (!item.isChecked && (!!item.dealerActiveId||!!item.userDealerId)) {
                    param.removeList.push(item.dealerActiveId || item.userDealerId);
                }
            }

            $scope.selectSingle = function (item) {
                var selectAll = false;
                if (!item.isChecked) {
                    selectAll = false;
                } else {
                    if (!checkAll()) {
                        selectAll = false;
                    } else {
                        selectAll = true;
                    }
                }
                $scope.markInfo.allChecked = selectAll;

                var param = {
                    removeList: [],
                    dealerList: []
                };
                handleSaveOrRemoveData(param, item);

                saveOrRemove(param);
            };

            function saveOrRemove(param) {
                if (angular.isDefined($scope.callBack())) {
                    $scope.callBack()(param).then(() => {
                        getLeftData();
                    })
                }
            }

            (function () {
                getLeftData(1);
            })();
        }])

        .directive('ybTimeLine', ["$timeout", function () {
            return {
                restrict: 'A',
                replace: true,
                scope: {
                    dataModel: '=?ngModel',
                    canEnter: "=",
                    canNotReceive: "=",
                    timeFrameNew: "=",
                    enterFunc: "&",
                    receiveFunc: "&",
                },
                templateUrl: 'js/directive/tpl/timeLine.html',
                controller: 'TimeLineCtrl'
            }
        }])
        .controller('TimeLineCtrl', ["$scope", "ybWidget", "ybHttp", "$filter", "EventBus", function ($scope, ybWidget, ybHttp, $filter, EventBus) {
            $scope.showCurTime = true;
            $scope.formShow = false;
            $scope.curTime = new Date().getTime();
            $scope.submitted = false;

            function setTimeShow(data) {
                if (data.length === 0) {
                    return;
                }
                var lastDataDate = new Date(data[data.length - 1].createDate).getTime();
                if ($filter("YbDate")($scope.curTime) === $filter("YbDate")(lastDataDate)) {
                    $scope.showCurTime = false;
                }
            }

            $scope.switchForm = function () {
                $scope.formShow = !$scope.formShow;
            };

            $scope.goodsReceive = function () {
                $scope.receiveFunc();
            };

            $scope.submit = function () {
                if (!$scope.timeFrameNew.address) {
                    $scope.submitted = true;
                    return;
                }
                $scope.timeFrameNew.createDate = $scope.curTime;
                $scope.enterFunc();
            };

            EventBus.Subscribe("setTimeShow", setTimeShow);

            $scope.$on("$destroy", function () {
                EventBus.Unsubscribe("setTimeShow", setTimeShow);
            });

            EventBus.Subscribe("entryTimeFrame", entryTimeFrame);

            function entryTimeFrame() {
                $scope.timeFrameNew.address = "";
                $scope.formShow = false;
                $scope.curTime = new Date().getTime();
                setTimeShow($scope.dataModel);
            }

            $scope.$on("$destroy", function () {
                EventBus.Unsubscribe("entryTimeFrame", entryTimeFrame);
            });

        }])

        .directive('ybFormClear', ["$timeout", function () {
            return {
                restrict: 'A',
                replace: true,
                scope: {
                    dataModel: '=?ngModel',
                    tipsName: "@",
                    formRequire: "=", // 原来的formRequire为: "@"，此处修改是为了取父作用域的变量，使该参数变得可配
                    selectObj: "&",
                    clearForm: "&",
                    inputDisabled: '=',
                    hideClear: '='
                },
                templateUrl: 'js/directive/tpl/formClear.html',
                link: function (scope) {

                    isAllowI18n(scope);

                    scope.tipName = '请选择' + scope.tipsName;
                    scope.tipNameClear = '清空' + scope.tipsName;
                }
            }
        }])

        //工具栏类
        .directive("ybAdvanceSearch", ['$document', function ($document) {
            return {
                restrict: "A",
                replace: "true",
                scope: {
                    showToolbar: '=',
                    maskClosable: '=?',
                    searchData: "&",
                    resetData: "&",
                    datePicker: "@",
                    hideDate: "&"
                },
                transclude: true,
                templateUrl: "js/directive/tpl/advanceSearch.html",
                link: function (scope) {

                    isAllowI18n(scope);

                    function closePopup() {
                        scope.showToolbar = false;
                    }

                    scope.cancel = function () {
                        closePopup()
                    };

                    scope.hideDatePicker = function () {
                        if (!!scope.datePicker) {
                            scope.hideDate();
                        }
                    };

                    scope.$watch("showToolbar", function (n, o) {
                        if (n) {
                            $document.on('keyup', function (e) {
                                var theEvent = e || window.event;
                                const tar = theEvent.target || theEvent.srcElement;
                                var code = theEvent.keyCode || theEvent.which || theEvent.charCode;
                                if (code == 13 && tar.localName != 'textarea') {
                                    scope.$apply(scope.searchData);
                                }
                            });
                        } else {
                            $document.off('keyup');
                        }
                    });

                    if (angular.isUndefined(scope.maskClosable)) {
                        scope.maskClosable = true; // 是否允许点击空白处关闭弹框，默认允许
                    }

                    $document.on('click', function () {
                        if (!!scope.showToolbar && !!scope.maskClosable) {
                            scope.$apply(function () {
                                closePopup();
                            });
                        }
                    });
                }
            }
        }])

        .directive("ybPrintConf", ['$document', function ($document) {
            return {
                restrict: "A",
                replace: "true",
                scope: {
                    showToolbar: '=',
                    printConf: "=?ngModel",
                    hideMainCode: "="
                },
                templateUrl: "js/directive/tpl/printConf.html",
                link: function (scope, element, attrs, ctrl) {

                    isAllowI18n(scope);

                    const printTypes = [
                        {
                            id: 0,
                            name: "集团模板"
                        },
                        {
                            id: 1,
                            name: "铲运专有模板"
                        },
                        {
                            id: 2,
                            name: "挖机大模板"
                        },
                        {
                            id: 3,
                            name: "挖机中模板"
                        },
                        {
                            id: 4,
                            name: "挖机小模板"
                        },
                        {
                            id: 5,
                            name: "进出口模板"
                        },
                        {
                            id: 7,
                            name: "巴西模板"
                        },
                        {
                            id: 8,
                            name: "铲运矿机模板"
                        },
                        {
                            id: 9,
                            name: "中模板"
                        },
                    ];

                    function closePopup() {
                        scope.showToolbar = false;
                    }

                    scope.cancel = function () {
                        closePopup()
                    };

                    scope.ok = function () {
                        closePopup();
                    };

                    if (scope.$root.isWJ) {
                        scope.printConf.printType = 2;
                    } else if (scope.$root.isJCHK) {
                        scope.printConf.printType = 5;
                    } else if (scope.$root.isNJ) {
                        scope.printConf.printType = 9;
                    } else {
                        scope.printConf.printType = 0;
                    }

                    $document.ready(function () {
                        if (scope.printConf.printType == 5) {
                            scope.printTypeList = printTypes.filter(p => p.id == 5);
                        } else {
                            scope.printTypeList = printTypes;
                        }
                    });

                    $document.on('click', function () {
                        if (!!scope.showToolbar) {
                            scope.$apply(function () {
                                closePopup();
                            });
                        }
                    });
                }
            }
        }])
        // 表格操作类
        .directive("ybColConfig", ["$document", "$timeout", 'ybWidget', "ybHttp", "MESG_TYPE", "EventBus", function ($document, $timeout, ybWidget, ybHttp, MESG_TYPE, EventBus) {
            return {
                restrict: "EA",
                replace: "true",
                scope: {
                    showToolbar: '=',
                    dataModel: "=?ngModel", // 绑定数据模型
                    colFixed: "=", // 包含固定列
                    fixedWidth: "=", // 固定列的宽
                    scrollWidth: "=", // 滚动列的宽
                    hasCheckCol: "@", // 是否有选择列
                    setTbStyle: "&",
                    hideSortColumn: '@', // 是否隐藏列排序，针对固定写死合并单元格的table无法排序
                },
                templateUrl: "js/directive/tpl/colConfig.html",
                link: function (scope) {
                    isAllowI18n(scope);
                    scope.selectRow = -1;
                    var watcher = scope.$watch("showToolbar", function (value, oldValue) {
                        if (!!value) {
                            scope.configList = angular.copy(scope.dataModel.tableCol);
                        }
                    });
                    scope.$on('$destroy', function () {
                        watcher();
                        watcher = null;
                    });
                    scope.showBtn = true
                    scope.changeTab = function (value) {
                        if (value == 3) {
                            scope.showBtn = false
                        } else {
                            scope.showBtn = true
                        }
                    }
                    scope.setCol = function (close) {
                        scope.dataModel.tableCol = angular.copy(scope.configList);
                        scope.selectRow = -1;
                        setTabWidth();
                        if (!!close) {
                            closePopup();
                        }
                    };

                    function setTabWidth() {
                        var fixedWidth = 0;
                        var scrollWidth = 0;
                        if (!!scope.hasCheckCol && !!scope.colFixed) {
                            fixedWidth = 40;
                        }
                        for (var i = 0, len = scope.dataModel.tableCol.length; i < len; i++) {
                            if (!!scope.dataModel.tableCol[i].isShow && !!scope.dataModel.tableCol[i].isFixed) {
                                fixedWidth += scope.dataModel.tableCol[i].width;
                            }
                            if (!!scope.dataModel.tableCol[i].isShow && !scope.dataModel.tableCol[i].isFixed) {
                                scrollWidth += scope.dataModel.tableCol[i].width;
                            }
                        }
                        scope.dataModel.fixedWidth = fixedWidth;
                        scope.dataModel.scrollWidth = scrollWidth;
                        $timeout(function () {
                            scope.setTbStyle();
                        });
                    }

                    scope.cancel = function () {
                        scope.configList = angular.copy(scope.dataModel.tableCol);
                        closePopup();
                    };

                    scope.moveIndex = function (index, type) {
                        var curItem = angular.copy(scope.configList[index]);
                        var targetIndex = 0;
                        if (type === "up") {
                            targetIndex = index - 1;
                        }
                        if (type === "down") {
                            targetIndex = index + 1;
                        }
                        scope.selectRow = targetIndex;
                        scope.configList[index] = scope.configList[targetIndex];
                        scope.configList[targetIndex] = curItem;
                    };

                    function closePopup() {
                        scope.showToolbar = false;
                    }

                    $document.on('click', function () {
                        if (!!scope.showToolbar) {
                            scope.$apply(function () {
                                closePopup();
                            });
                        }
                    });
                }
            }
        }])

        .directive('ybTableFixed', [function () {
            return {
                restrict: 'AE',
                scope: {
                    eleCount: "@",
                    scrollArea: "@",
                    autoHeight: "=" // 是否自动计算表格高度
                },
                link: function ($scope, element) {
                    var mouseTarget = ""; // 鼠标悬停的目标元素
                    var eleScrollIndexS = 0; // 上下左右滚动元素的索引 -- 主滚动元素
                    var eleScrollIndexX = 0; // 跟随左右滚动元素的索引 -- 标题
                    var eleScrollIndexY = 0; // 跟随上下滚动元素的索引 -- 固定列
                    var menuElement = angular.element(document.getElementById("contextMenu"));
                    if (angular.isUndefined($scope.scrollArea)) {
                        eleScrollIndexS = 1;
                        eleScrollIndexX = 0;
                    } else {
                        if ($scope.scrollArea === "left") {
                            eleScrollIndexS = $scope.eleCount / 2;
                            eleScrollIndexX = 0;
                            eleScrollIndexY = $scope.eleCount - 1;
                        }
                        if ($scope.scrollArea === "right") {
                            eleScrollIndexS = $scope.eleCount - 1;
                            eleScrollIndexX = ($scope.eleCount / 2) - 1;
                            eleScrollIndexY = $scope.eleCount / 2;
                        }
                    }

                    if ($scope.autoHeight) {
                        setTimeout(() => {
                            const eleChild = element[0].getElementsByTagName('hy-layout-table-fixed');
                            if (eleChild.length == 0) {
                                return;
                            }

                            const eleChidChild = eleChild[0].children;
                            
                            handleEventFun(eleChild);

                            setTableHeight();
                            startObserve();

                            function setTableHeight() {
                                const trSize = eleChidChild[2].getElementsByTagName('tr').length;
                                const dataHeight = trSize * 40 + 60; // 40每行行高；60单元格内校验错误信息区域的预留高度
                                const tdScrollY = angular.element(eleChidChild[2]);
                                const tdScroll = angular.element(eleChidChild[3]);
                                tdScrollY.css('height', dataHeight + 'px');
                                tdScroll.css('height', dataHeight + 'px');

                                const hyTableFixed = angular.element(element[0].parentElement);
                                hyTableFixed.css('display', 'block');
                                hyTableFixed.css('height', dataHeight + 40 + 'px'); // 40表格底部横向滚动条预留高度
                            }

                            function startObserve() {
                                // 选择需要观察变化的父元素
                                const targetNode = eleChidChild[2].getElementsByTagName('tbody')[0];
     
                                // 配置观察选项:
                                const config = { childList: true };
                                
                                // 当观察到变化时执行的回调函数
                                const callback = function(mutationsList, observer) {
                                    const needReCalHeight = mutationsList.some(mutation => {
                                        const changeEle = mutation.addedNodes[0] || mutation.removedNodes[0] || {};
                                        return changeEle.nodeName === 'TR'
                                    });

                                    if (needReCalHeight) {
                                        // 重新计算表格高度
                                        setTableHeight();
                                    }
                                };
                                
                                // 创建一个观察器实例并传入回调函数
                                const observer = new MutationObserver(callback);
                                
                                // 开始观察目标节点
                                observer.observe(targetNode, config);
                                
                                // 停止观察：
                                // observer.disconnect();
                            }

                        }, 50);
                    } else {
                        handleEventFun(element);
                    }

                    function handleEventFun(element) {
                        element[0].children[eleScrollIndexY].onmouseover = function () {
                            mouseTarget = "scrollY";
                        };
                        element[0].children[eleScrollIndexY].onmouseout = function () {
                            mouseTarget = "";
                        };
                        element[0].children[eleScrollIndexS].onmouseover = function () {
                            mouseTarget = "scrollS";
                        };
                        element[0].children[eleScrollIndexS].onmouseout = function () {
                            mouseTarget = "";
                        };

                        element[0].children[eleScrollIndexY].onscroll = function () {
                            if (mouseTarget === "scrollY") {
                                var scrollTop = element[0].children[eleScrollIndexY].scrollTop;
                                element[0].children[eleScrollIndexS].scrollTop = scrollTop;
                            }
                        };

                        element[0].children[eleScrollIndexS].onscroll = function () {
                            if (mouseTarget === "scrollS") {
                                var scrollTop = element[0].children[eleScrollIndexS].scrollTop;
                                var scrollLeft = element[0].children[eleScrollIndexS].scrollLeft;
                                if (angular.isDefined($scope.scrollArea)) {
                                    element[0].children[eleScrollIndexY].scrollTop = scrollTop;
                                }
                                element[0].children[eleScrollIndexX].scrollLeft = scrollLeft;
                            }
                            if (menuElement.length > 0) {
                                menuElement.css("display", "none");
                            }
                        };
                    }
                }
            };
        }])

        .directive('ybThDrag', [function () {
            return {
                restrict: 'A',
                scope: {
                    colWidth: "=",
                    targetWidth: "=",
                    fixedWidth: "="
                },
                link: function (scope, element, attrs, $event) {
                    var tableWidth = 0;
                    var thisWidth = 0;
                    var finalPosition = 0;
                    var tableActualWidth = 0;
                    var moveDistance = 0; // 鼠标移动的距离
                    element[0].onmousedown = function ($event) {
                        var e = $event || window.event;
                        var disX = e.clientX;
                        tableWidth = parseInt(scope.targetWidth);
                        thisWidth = element.parent()[0].offsetWidth;
                        document.onmousemove = function ($event) {
                            var ev = $event || window.event;
                            moveDistance = ev.clientX - disX;
                            finalPosition = thisWidth + moveDistance;
                            tableActualWidth = tableWidth + moveDistance;
                            if (finalPosition < 80) {
                                return
                            }
                            element.parent()[0].width = finalPosition;
                            scope.$apply(function () {
                                scope.colWidth = finalPosition;
                                scope.targetWidth = tableActualWidth;
                                if (angular.isDefined(scope.fixedWidth)) {
                                    scope.fixedWidth = {
                                        left: tableActualWidth + "px"
                                    };
                                }
                            });
                        };

                        document.onmouseup = function () {
                            element.releaseCapture && element.releaseCapture();
                            document.onmousemove = null;
                            document.onmouseup = null;
                        };
                    };
                }
            }
        }])

        .directive('ybTheadOperate', [function () {
            return {
                restrict: "EA",
                replace: "true",
                scope: {
                    dataModel: "=?ngModel",
                    colWidth: "=",
                    targetWidth: "=",
                    fixedWidth: "="
                },
                templateUrl: "js/directive/tpl/theadOperate.html",
                link: function (scope, element, attrs, $event) {

                    isAllowI18n(scope);

                    var tableWidth = 0;
                    var thisWidth = 0;
                    var finalPosition = 0;
                    var tableActualWidth = 0;
                    var moveDistance = 0; // 鼠标移动的距离
                    var dragEle = element.children().children()[0];
                    dragEle.onmousedown = function ($event) {
                        var e = $event || window.event;
                        var disX = e.clientX;
                        tableWidth = parseInt(scope.targetWidth);
                        thisWidth = element.parent()[0].offsetWidth;
                        document.onmousemove = function ($event) {
                            var ev = $event || window.event;
                            moveDistance = ev.clientX - disX;
                            finalPosition = thisWidth + moveDistance;
                            tableActualWidth = tableWidth + moveDistance;
                            if (finalPosition < 80) {
                                return
                            }
                            element.parent()[0].width = finalPosition;
                            scope.$apply(function () {
                                scope.dataModel.width = finalPosition;
                                scope.targetWidth = tableActualWidth;
                                if (angular.isDefined(scope.fixedWidth)) {
                                    scope.fixedWidth = {
                                        left: tableActualWidth + "px"
                                    };
                                }
                            });
                        };

                        document.onmouseup = function () {
                            element.releaseCapture && element.releaseCapture();
                            document.onmousemove = null;
                            document.onmouseup = null;
                        };
                    };
                }
            }
        }])

        .directive("ybDownload", ['$compile', 'ybWidget', 'MESG_TYPE', '$timeout', "$http", "$rootScope", "ybConfig", "UserContextService", function ($compile, ybWidget, MESG_TYPE, $timeout, $http, $rootScope, ybConfig, UserContextService) {
            return {
                restrict: "A",
                replace: "false",
                scope: {
                    downloadMethod: "=?",
                    downloadUrl: "=",
                    downloadParam: "=",
                    downloadKey: "@",
                    checkCallback: "&",
                    downloadDuration: "=",
                    isAjax: "@",
                    onError: "&",
                },
                link: function (scope, element, attrs) {
                    scope.downloadMethod = scope.downloadMethod || "post";
                    const downloadUrlNew = scope.downloadUrl.replace('/dev/', '/devrpt/');
                    scope.downloadUrl = `${downloadUrlNew}?SC-AUTH=${localStorage.getItem("ScAuthC")}`;
                    var template = "<div class='hidden'>" +
                        "<form action='{{downloadUrl}}' method='{{downloadMethod}}' target='ybDownloadFileForm'>" +
                        "<div ng-repeat='(key,value) in downLoadParamTemp'>" +
                        "<textarea name='{{key}}' ng-model='value'></textarea>" +
                        "</div>" +
                        "</form>" +
                        "</div>" +
                        "<iframe name='ybDownloadFileForm' ng-hide='true'></iframe>";
                    var formTemplate = angular.element(template);
                    $compile(formTemplate)(scope);
                    element.after(formTemplate);
                    element.on("click", submitRequest);
                    scope.$watch('downloadParam', function () {
                        scope.downLoadParamTemp = UserContextService.RemoveEmptyValues(angular.copy(scope.downloadParam));
                    }, true);

                    var exportNow = true;

                    function submitRequest() {
                        if ($rootScope.isWJ && ybConfig.isPublicNetwork()) {
                            // 挖机主机厂 外网访问时 无导出权限
                            ybWidget.ShowMessage('无权限导出数据！', MESG_TYPE.Warn);
                            return
                        }

                        var isValid = true;
                        if (scope.checkCallback) {
                            isValid = scope.checkCallback();
                            if (isValid == undefined) {
                                isValid = true;
                            }
                        }
                        if (!isValid) {
                            return;
                        }
                        if (scope.downloadDuration && !exportNow) {
                            var msg = "由于数据量过大，请在" + scope.downloadDuration + "分钟内不要重复点击！"
                            ybWidget.ShowMessage(msg, MESG_TYPE.Warn);
                            return;
                        }
                        // 多少秒内不能再导出
                        if (scope.downloadDuration) {
                            exportNow = false;
                            $timeout(function () {
                                exportNow = true;
                            }, parseFloat(scope.downloadDuration) * 60 * 1000);
                        }
                        $timeout(function () {
                            if (angular.isDefined(scope.downloadKey)) {
                                // 部分导出
                                if (scope.downLoadParamTemp[scope.downloadKey].length === 0) {
                                    ybWidget.ShowMessage("请选择需要导出的数据行", MESG_TYPE.Warn);
                                } else {
                                    excuteExport();
                                }
                            } else {
                                // 全部导出
                                scope.$apply(function () {
                                    if (!!scope.downLoadParamTemp) {
                                        angular.forEach(Object.keys(scope.downLoadParamTemp), function (item) {
                                            if (typeof (scope.downLoadParamTemp[item]) === "string") {
                                                scope.downLoadParamTemp[item] = scope.downLoadParamTemp[item].replace(/[\r\n]/g, ",");
                                            }
                                        });
                                    }
                                });
                                excuteExport();
                            }
                        });
                    }

                    function excuteExport() {
                        if (scope.isAjax === 'true') {
                            // 注：使用ajax请求时（即以json的方式传参）
                            // 部分导出参数对接时：前后端约定好均使用对象，后端定义的对象里的key 和 前端定义的downloadKey需保持一致。
                            $http({
                                method: 'post',
                                url: scope.downloadUrl,
                                data: scope.downLoadParamTemp,
                                responseType: 'blob',
                                headers: { 'language': $rootScope.isEN ? 'en' : 'zh' }
                            }).then(function (resp) {
                                const blob = new Blob([resp.data])

                                const fileReader = new FileReader()
                                fileReader.onload = (event) => {
                                    const readResult = event.target.result
                                    try {
                                        // JSON.parse方法未抛异常：异常的导出文件流(因为异常的文件流是符合json规则的字符串)

                                        const errMsg = JSON.parse(readResult);
                                        if (angular.isDefined(scope.onError())) {
                                            scope.onError()(errMsg);
                                        } else {
                                            ybWidget.ShowMessage(errMsg.message, MESG_TYPE.Error);
                                        }
                                    } catch (error) {
                                        // JSON.parse方法抛异常：正常的导出文件流(因为正常的文件流是不符合json规则的字符串)

                                        // 从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名;
                                        const contentDisposition = resp.headers()['content-disposition'];
                                        const result = contentDisposition.split('filename=');
                                        const filename = decodeURI(result[1]);

                                        const aTag = document.createElement('a');
                                        aTag.href = window.URL.createObjectURL(blob);// 创建下载的链接
                                        aTag.download = filename;// 下载后文件名
                                        aTag.click();// 点击下载

                                        window.URL.revokeObjectURL(blob);//释放掉blob对象
                                    }
                                }
                                fileReader.readAsText(blob)
                            }).catch(function (resp) {
                                console.log('excuteExportErr', resp)
                            })
                        } else {
                            formTemplate[0].firstChild.submit();
                        }
                    }
                }
            };
        }])

        .directive("ybWordCount", ['$parse', '$compile', function ($parse, $compile) {
            return {
                restrict: "A",
                require: "?ngModel",
                scope: {
                    maxSize: "="
                },
                link: function (scope, element, attrs, ctrl) {
                    var ngModelCtrl = ctrl;
                    if (!ngModelCtrl) {
                        return;
                    }
                    if (!scope.maxSize) {
                        return;
                    }
                    var showReminder = angular.isDefined(attrs.showReminder) ? scope.$eval(attrs.showReminder) : true;
                    var template = "<div style='color:#bbb; font-size:12px; line-height: 14px; height: 14px; margin-top: 10px;'>还可以输入{{surplusSize}}字</div>";
                    var wordcountTemplate = angular.element(template);
                    scope.surplusSize = scope.maxSize;
                    $compile(wordcountTemplate)(scope);
                    element.after(wordcountTemplate);

                    ngModelCtrl.$parsers.push(function (value) {
                        if (angular.isUndefined(value) || value.length <= 0) {
                            scope.surplusSize = scope.maxSize;
                            return value;
                        }
                        return countCurrentString(value);

                    });
                    ngModelCtrl.$formatters.unshift(function (value) {
                        var target = value;
                        if (!!value && value.length > 0 && scope.surplusSize == scope.maxSize) {
                            target = countCurrentString(value);
                        }
                        return target;
                    });

                    function countCurrentString(value) {
                        var currentCount = 0;
                        var target = value;
                        for (var i = 0, length = value.length; i < length; i++) {
                            if (value.charCodeAt(i) > 255) {
                                currentCount += 2;
                            } else {
                                currentCount += 1;
                            }
                            if (currentCount > scope.maxSize * 2) {
                                target = value.substring(0, i);
                                ngModelCtrl.$setViewValue(target);
                                ngModelCtrl.$render();
                                break;
                            }
                        }
                        scope.surplusSize = Math.floor((scope.maxSize * 2 - currentCount) / 2);
                        if (scope.surplusSize < 0) {
                            scope.surplusSize = 0;
                        }
                        return target;
                    }

                    if (showReminder) {
                        wordcountTemplate.css("display", "block");
                    } else {
                        wordcountTemplate.css("display", "none");
                    }
                }
            }
        }])

        .directive('qrCode', ['EventBus', function (EventBus) {
            return {
                restrict: 'A',
                replace: true,
                scope: {
                    qrText: "=?ngModel",
                    qrTicket: "@",
                    qrSize: "@"
                },
                link: function (scope, element, attrs) {
                    var qrcode = new QRCode(element[0], {
                        width: scope.qrSize || 100,
                        height: scope.qrSize || 100,
                        colorDark: "#000000",
                        colorLight: "#ffffff"
                    });
                    qrcode.clear();
                    qrcode.makeCode(scope.qrText || scope.qrTicket);
                }
            }
        }])

        .directive('ybEnter', ['$window', function ($window) {
            return {
                restrict: 'A',
                replace: true,
                link: function (scope, element, attrs) {
                    element.bind('keydown keypress', function (evt) {
                        var e = evt || $window.event;
                        if ((e.keyCode || e.which) == 13) {
                            scope.$apply(function () {
                                scope.$eval(attrs.ybEnter, {
                                    'event': e
                                });
                            });
                            if (e.preventDefault()) {
                                e.preventDefault()
                            } else {
                                e.returnValue = false;
                            }
                        }
                    });
                }
            }
        }])

        .directive("ybFocus", function () {
            return {
                restrict: "A",
                require: 'ngModel',
                link: function (scope, element, attrs, ctrl) {
                    ctrl.focused = false;
                    element.bind('focus', function (evt) {
                        scope.$apply(function () {
                            ctrl.focused = true;
                        });
                    }).bind('blur', function () {
                        scope.$apply(function () {
                            ctrl.focused = false;
                        });
                    });
                }
            };
        })

        .directive("ybCheckCircle", function () {
            return {
                scope: {
                    circleChecked: "=",
                    circleTitle: "@"
                },
                restrict: "A",
                replace: "true",
                template: "<div class='check-circle'>" +
                    "<i class='yb-icon ico-check base-color' ng-if='circleChecked'></i>" +
                    "<i class='yb-icon ico-check' ng-if='!circleChecked'></i><span>{{multiLan?(circleTitle|translate):circleTitle}}</span></div>",
                link: function (scope, element, attrs, ctrl) {
                    isAllowI18n(scope);
                    scope.circleTitle = scope.circleTitle || "设置默认";
                }
            };
        })

        .directive("ybBarChart", ['$timeout', 'EventBus', function ($timeout, EventBus) {
            return {
                restrict: "A",
                scope: {
                    xaxisTitle: "@", // X轴名称
                    chartAxis: "=" // echarts option对象
                },
                link: function (scope, elements, attrs) {
                    var curEle = elements[0];
                    var barChart = null;
                    var type = angular.isDefined(attrs.barType) ? attrs.barType : "normal";
                    var option = {};

                    // 数据柱竖排
                    var optionNormal = {
                        tooltip: {
                            trigger: 'axis',
                            axisPointer: { // 坐标轴指示器，坐标轴触发有效
                                type: 'shadow' // 默认为直线，可选为：'line' | 'shadow'
                            }
                        },
                        yAxis: [ // y坐标轴设置
                            {
                                type: 'value',
                                axisLine: {
                                    show: true
                                },
                                axisTick: {
                                    show: true
                                }
                            }
                        ],
                        calculable: true,
                        grid: {
                            left: '5%',
                            right: '5%',
                            bottom: '5%',
                            top: '15%',
                            containLabel: true
                        }
                    };

                    var toolbox = {
                        show: true,
                        right: 20,
                        feature: {
                            dataView: {
                                show: true,
                                readOnly: true,
                                optionToContent: function (opt) {
                                    const axisData = opt.xAxis[0].data;
                                    const series = opt.series;

                                    let thStr = `<th>${scope.xaxisTitle}</th>`
                                    for (let thItem of series) {
                                        thStr += `<th>${thItem.name}</th>`
                                    }
                                    const trTh = `<tr>${thStr}</tr>`

                                    let trTd = ''
                                    for (let i = 0, l = axisData.length; i < l; i++) {
                                        let tdStr = ''
                                        tdStr += `<td>${axisData[i]}</td>`
                                        for (let tdItem of series) {
                                            tdStr += `<td>${tdItem.data[i]}</td>`
                                        }
                                        trTd += `<tr>${tdStr}</tr>`
                                    }

                                    return `<table style="width:100%;" class="echarts-table"><tbody>${trTh}${trTd}</tbody></table>`;
                                },
                            },
                        }
                    };

                    if (scope.xaxisTitle) { // 设置X轴名称，即开启数据视图功能
                        optionNormal.toolbox = toolbox;
                    }

                    createEchartInstance();

                    scope.$watch("chartAxis", function (value, oldValue) {
                        if (oldValue !== value) {
                            updateEchartUI();
                        }
                    }, true);

                    function createEchartInstance() {
                        barChart = echarts.init(curEle);
                        updateOptionData();
                        barChart.setOption(option);

                        barChart.on('click', function (params) {
                            EventBus.Publish('onEchartsClick', params)
                        });
                    }

                    function updateOptionData() {
                        switch (type) {
                            case "normal":
                                barHandle();
                                break;
                            case "pie":
                                pieHandel();
                                break;
                        }
                    }

                    function barHandle() {
                        option = {
                            ...optionNormal,
                            ...scope.chartAxis
                        };
                    }

                    function pieHandel() {
                        option = {
                            title: {
                                text: scope.chartAxis.chartTitle
                            },
                            tooltip: {
                                trigger: 'item',
                                formatter: "{a} <br/>{b} : {d}%"
                            },
                            series: [
                                {
                                    name: '访问来源',
                                    type: 'pie',
                                    radius: '55%',
                                    data: scope.chartAxis.yData
                                }
                            ]
                        };
                    }

                    function updateEchartUI() {
                        if (barChart) {
                            barChart.clear();
                            updateOptionData();
                            barChart.setOption(option);
                        }
                    }

                    $timeout(function () {
                        barChart.resize();
                    });

                    window.onresize = function () {
                        barChart.resize();
                    }

                }
            }
        }])

        .directive("selectSendType", ['ybHttp', "ybWidget", "$q", function (ybHttp, ybWidget, $q) {
            return {
                restrict: "EA",
                replace: "true",
                scope: {
                    firstLevelModel: '=',
                    secondLevelModel: '=',
                    parentTypeName: '=',
                    childTypeName: '=',
                    supplierOrgId: '=',
                    isRequire: '=?',
                    isSap: '=',
                    isDealer: '=',
                    isDefault: '=',
                    isJch: '=', // 当前账号是否为进出口
                    isSupplierZx: '=', // 选择的接收单位是否是重型主机厂，配合isJch一起使用(解决的需求场景是：进出口登录时，采购订单接收单位选择了重型)
                },
                template: "<div>" +
                    "<div class='col-xs-6' style='padding-left: 0'>" +
                    "<select name='sendType' class='form-control' ng-click='check()' ng-model='firstLevelModel' ng-change='optionChanged(firstLevelModel, 0)'" +
                    "ng-options='item.code as (item.name| translate) for item in purchaseFirstLevelList' ng-required='isRequire' yb-focus>" +
                    "<option value=''>{{multiLan?('请选择'|translate):'请选择'}}</option>" +
                    "</select>" +
                    "</div>" +
                    "<div class='col-xs-6'  style='padding-right: 0'>" +
                    "<select name='purchaseChildType' class='form-control' ng-model='secondLevelModel' ng-change='optionChanged(secondLevelModel, 1)'" +
                    "ng-options='item.code as (item.name| translate) for item in purchaseSecondLevelList'>" +
                    "<option value=''>{{multiLan?('请选择'|translate):'请选择'}}</option>" +
                    "</select>" +
                    "</div>" +
                    "</div>",
                link: function (scope, element, attrs, ctrl) {
                    if (!angular.isDefined(scope.isRequire)) {
                        scope.isRequire = true;
                    }
                    scope.purchaseFirstLevelList = [];
                    scope.purchaseSecondLevelList = [];
                    isAllowI18n(scope)
                    scope.check = function () {
                        if (scope.isDealer && !scope.firstLevelModel && !scope.supplierOrgId) {
                            ybWidget.ShowMessage("请先选择接收单位");
                        }
                    };

                    scope.$watch('supplierOrgId', function () {
                        if (scope.isDealer || (scope.isJch && scope.isSupplierZx)) {
                            getFirstLevelList();
                        }
                    });

                    function getLevelList(parentId) {
                        if (parentId == "") {
                            return $q.reject();
                        }
                        if (scope.isDealer && !scope.supplierOrgId) {
                            return $q.reject();
                        }
                        var service = "device";
                        var reqUrl = "/sendMethodDictionary/list";
                        var param = {
                            pId: parentId
                        };

                        if (scope.isSap && !scope.isJch || scope.isSupplierZx && scope.isJch) {
                            param.orgId = scope.supplierOrgId;
                        }

                        return ybHttp.Post(service, reqUrl, param).then(function (resp) {
                            if (resp.code !== 0) {
                                ybWidget.ShowMessage(resp, MESG_TYPE.Error);
                                return;
                            }
                            return resp.value;
                        })
                    }

                    function setSecondLevelListByCode(parentCode) {
                        var parentId = "";
                        if (scope.purchaseFirstLevelList.length == 0) {
                            getFirstLevelList().then(function () {
                                getList();
                            })
                        } else {
                            getList();
                        }

                        function getList() {
                            angular.forEach(scope.purchaseFirstLevelList, function (item) {
                                if (item.code === parentCode) {
                                    parentId = item.id;
                                }
                            });
                            getLevelList(parentId).then(function (data) {
                                scope.purchaseSecondLevelList = data;
                            });
                        }

                    }

                    scope.optionChanged = function (code, level) {
                        if (level === 0) {
                            scope.purchaseSecondLevelList = [];
                            scope.secondLevelModel = "";
                        }
                        var targetList = level === 0 ? scope.purchaseFirstLevelList : scope.purchaseSecondLevelList;
                        var targetName = level === 0 ? "parentTypeName" : "childTypeName";
                        for (var i = 0; i < targetList.length; i++) {
                            var item = targetList[i];
                            if (code === item.code) {
                                scope[targetName] = item.name;
                                break;
                            }
                        }
                    };

                    scope.$watch('firstLevelModel', function (newValue) {
                        if (!!newValue) {
                            setSecondLevelListByCode(newValue);
                        } else {
                            scope.purchaseSecondLevelList = [];
                            scope.secondLevelModel = "";
                        }
                    });

                    function getFirstLevelList() {
                        return getLevelList("0").then(function (data) { // 父节点id：0
                            scope.purchaseFirstLevelList = data;
                            if (scope.isDefault) {
                                for (var i = 0, len = scope.purchaseFirstLevelList.length; i < len; i++) {
                                    if (scope.purchaseFirstLevelList[i].code === "PZ") {
                                        // 发运方式默认值 “PZ”，该值在页面 基础数据-发货方式 可以修改，一经修改默认值就会有bug
                                        scope.firstLevelModel = scope.purchaseFirstLevelList[i].code;
                                        scope.parentTypeName = scope.purchaseFirstLevelList[i].name;
                                    }
                                }
                            }
                        });
                    }

                    if (!scope.isDealer) {
                        getFirstLevelList();
                    }

                }
            }
        }])

        .directive("selectPurchaseType", ['ybHttp', "ybWidget", "$q", "$timeout", function (ybHttp, ybWidget, $q, $timeout) {
            return {
                restrict: "EA",
                replace: "true",
                scope: {
                    firstLevelModel: '=',
                    secondLevelModel: '=',
                    parentTypeName: '=',
                    childTypeName: '=',
                    supplierOrgId: '=',
                    isSap: '=',
                    isDealer: '=',
                    isDefault: '=',
                    optionChange: '&',
                    stockType: '=', // 2:补库汇总新增 3:紧急汇总新增
                },
                template: "<div>" +
                    "<div class='col-xs-6' style='padding-left: 0px;'>" +
                    "<select name='purchaseType' class='form-control' ng-model='firstLevelModel' ng-change='optionChanged(firstLevelModel, 0)'" +
                    "ng-options='item.code as (item.name|translate) for item in purchaseFirstLevelList' required yb-focus>" +
                    "<option value=''>{{multiLan?('请选择'|translate):'请选择'}}</option>" +
                    "</select>" +
                    "</div>" +
                    "<div class='col-xs-6'  style='padding-right: 0px;'>" +
                    "<select name='secondPurchaseType' class='form-control' ng-click='check()' ng-model='secondLevelModel' ng-change='optionChanged(secondLevelModel, 1)'" +
                    "ng-options='item.code as (item.name|translate) for item in purchaseSecondLevelList' ng-required='purchaseSecondLevelList.length>0' yb-focus>" +
                    "<option value=''>{{multiLan?('请选择'|translate):'请选择'}}</option>" +
                    "</select>" +
                    "</div>" +
                    "</div>",
                link: function (scope, element, attrs, ctrl) {
                    scope.purchaseFirstLevelList = [];
                    scope.purchaseSecondLevelList = [];
                    scope.newValue = "";
                    isAllowI18n(scope);

                    function getLevelList(parentId) {
                        var service = "device";
                        var reqUrl = "/purchaseDictionary/list";
                        var param = {
                            pId: parentId
                        };
                        if (scope.isSap) {
                            param.orgId = scope.supplierOrgId;
                        }

                        if (parentId == "") {
                            return $q.reject();
                        }
                        return ybHttp.Post(service, reqUrl, param).then(function (resp) {
                            if (resp.code !== 0) {
                                ybWidget.ShowMessage(resp, MESG_TYPE.Error);
                                return;
                            }
                            return resp.value;
                        })
                    }

                    scope.check = function () {
                        if (scope.isDealer && !scope.secondLevelModel && !scope.supplierOrgId) {
                            ybWidget.ShowMessage("请先选择接收单位");
                        }
                    };

                    scope.$watch('supplierOrgId', function () {
                        if (scope.isDealer) {
                            getFirstLevelList();
                        }
                    });

                    function setSecondLevelListByCode(parentCode) {
                        var parentId = "";
                        if (scope.purchaseFirstLevelList.length == 0) {
                            getFirstLevelList().then(function () {
                                getList();
                            })
                        } else {
                            getList();
                        }

                        function getList() {
                            angular.forEach(scope.purchaseFirstLevelList, function (item) {
                                if (item.code === parentCode) {
                                    parentId = item.id;
                                }
                            });
                            getLevelList(parentId).then(function (data) {
                                scope.purchaseSecondLevelList = data;
                            });
                        }

                    }

                    scope.optionChanged = function (code, level) {
                        if (level === 0) {
                            scope.purchaseSecondLevelList = [];
                            scope.secondLevelModel = "";
                        }
                        var targetList = level === 0 ? scope.purchaseFirstLevelList : scope.purchaseSecondLevelList;
                        var targetName = level === 0 ? "parentTypeName" : "childTypeName";
                        for (var i = 0; i < targetList.length; i++) {
                            var item = targetList[i];
                            if (code === item.code) {
                                scope[targetName] = item.name;
                                break;
                            }
                        }
                        if (angular.isDefined(attrs.optionChange)) {
                            $timeout(function () {
                                scope.optionChange();
                            });
                        }
                    };

                    scope.$watch('firstLevelModel', function (newValue) {
                        if (!!newValue) {
                            setSecondLevelListByCode(newValue);
                            scope.newValue = newValue;
                        } else {
                            scope.purchaseSecondLevelList = [];
                            scope.secondLevelModel = "";
                        }
                    });

                    function getFirstLevelList() {
                        return getLevelList("0").then(function (data) {
                            if (scope.$root.isDL) {
                                scope.purchaseFirstLevelList = data.filter(df => ['1', '2', '6'].includes(df.code)); // 紧急、补库、重要
                            } else {
                                scope.purchaseFirstLevelList = data;
                            }

                            if (scope.isDefault) {
                                for (var i = 0, len = scope.purchaseFirstLevelList.length; i < len; i++) {
                                    if (scope.purchaseFirstLevelList[i].name === "补库") {
                                        scope.firstLevelModel = scope.purchaseFirstLevelList[i].code;
                                    }
                                }
                            }
                        });
                    }
                    getFirstLevelList();
                }
            }
        }])

        .directive('toggle', ['$timeout', function ($timeout) {
            return {
                restrict: 'EA',
                replace: true,
                scope: {
                    'ngModel': '=',
                    'ybDisabled': '=ybDisabled',
                    'ybClick': '&'
                },
                templateUrl: "js/directive/tpl/toggle.html",
                link: function (scope, elm, attr) {
                    isAllowI18n(scope);

                    scope.handleToggle = function () {
                        $timeout(function () {
                            scope.ybClick();
                        });
                    }
                }
            }
        }])

        .directive("searchPurchaseType", ['ybHttp', "ybWidget", "$q", function (ybHttp, ybWidget, $q) {
            return {
                restrict: "EA",
                scope: {
                    firstLevelModel: '=',
                    secondLevelModel: '='
                },
                template: "<div class='form-group clearfix'>" +
                    "<label class='control-label'>{{multiLan?('采购方式'|translate):'采购方式'}}：</label>" +
                    "<select name='searchPurchaseType' class='form-control' ng-model='firstLevelModel'" +
                    "ng-options='item.code as (multiLan?(item.name|translate):item.name) for item in purchaseFirstLevelList'>" +
                    "<option value=''>{{multiLan?('请选择'|translate):'请选择'}}</option>" +
                    "</select>" +
                    "</div>" +
                    "<div class='form-group clearfix'>" +
                    "<label class='control-label'></label>" +
                    "<select name='searchPurchaseChildType' class='form-control' ng-model='secondLevelModel'" +
                    "ng-options='item.code as (multiLan?(item.name|translate):item.name) for item in purchaseSecondLevelList'>" +
                    "<option value=''>{{multiLan?('请选择'|translate):'请选择'}}</option>" +
                    "</select>" +
                    "</div>",
                link: function (scope, element, attrs, ctrl) {

                    isAllowI18n(scope);

                    scope.purchaseFirstLevelList = [];
                    scope.purchaseSecondLevelList = [];

                    function getLevelList(parentId) {
                        var service = "device";
                        var reqUrl = "/purchaseDictionary/list";
                        var param = {
                            pId: parentId
                        };
                        if (parentId == "") {
                            return $q.reject();
                        }
                        return ybHttp.Post(service, reqUrl, param).then(function (resp) {
                            if (resp.code !== 0) {
                                ybWidget.ShowMessage(resp, MESG_TYPE.Error);
                                return;
                            }
                            return resp.value;
                        })
                    }

                    function setSecondLevelListByCode(parentCode) {
                        var parentId = "";
                        if (scope.purchaseFirstLevelList.length == 0) {
                            getFirstLevelList().then(function () {
                                getList();
                            })
                        } else {
                            getList();
                        }

                        function getList() {
                            angular.forEach(scope.purchaseFirstLevelList, function (item) {
                                if (item.code === parentCode) {
                                    parentId = item.id;
                                }
                            });
                            getLevelList(parentId).then(function (data) {
                                scope.purchaseSecondLevelList = data;
                            });
                        }

                    }

                    scope.$watch('firstLevelModel', function (newValue) {
                        if (!!newValue) {
                            setSecondLevelListByCode(newValue);
                        } else {
                            scope.purchaseSecondLevelList = [];
                            scope.secondLevelModel = "";
                        }
                    });

                    function getFirstLevelList() {
                        return getLevelList("0").then(function (data) {
                            scope.purchaseFirstLevelList = data;
                        });
                    }

                    getFirstLevelList();
                }
            }
        }])
        //图片上传
        .directive("ybUpload", ["ybHttp", "ybWidget", "MESG_TYPE", "Upload", "ybConfig", function (ybHttp, ybWidget, MESG_TYPE, Upload, ybConfig) {
            return {
                restrict: "AE",
                scope: {
                    dataModel: '=ngModel',
                    onlyView: '=?', // 是否仅查看(默认否)
                    multiple: '=?', // 是否支持多图片上传(默认是)
                    cropable: '=?', // 是否支持裁剪(默认是)
                    maxImgAmount: '=?', // 允许上传的图片最大数量（默认3张）
                    maxImgSize: '=?', // 允许上传的图片单张最大尺寸（默认1M）
                    urlRoot: '@?', // 图片上传接口的默认根路径（上传接口所在服务的路由名称）
                    urlType: '@?', // 图片默认根路径类型（取自ftp、oss、minio）
                    mnDir: '@?' // minio存储的目录
                },
                replace: true,
                templateUrl: "js/directive/tpl/uploadImage.html",
                link: function ($scope) {
                    /**
                     * 在图片上传、裁剪后上传 过程中，照片数组dataModel 对象里涉及的字段以及说明
                     * 
                     * 字段        类型      字段意义
                     * 
                     * img:        File     调图片上传接口时使用--------------------------------文件上传组件产生
                     * base64:     String   图片裁剪时使用（也可在图片展示时使用）---------------文件上传组件产生
                     * 
                     * cropImg     File     裁剪后的图片调图片上传接口时使用---------------------裁剪组件产生
                     * cropBase64  String   裁剪后的图片展示时使用-------------------------------裁剪组件产生
                     * 
                     * imgUrl:     String   调图片上传接口返回的信息，新增编辑 调保存接口时使用---接口返回
                     * imgUrlShow: String   对imgUrl处理后的信息（拼接了域名），页面展示时使用----前端处理产生
                     * hasUpload:  Boolean  标识该张图片是否已上传，页面展示时使用----------------前端处理产生
                     */
        
                    $scope.dataModel = !$scope.dataModel ? [] : $scope.dataModel;
                    $scope.onlyView = angular.isUndefined($scope.onlyView) ? false : $scope.onlyView;
                    $scope.multiple = angular.isUndefined($scope.multiple) ? true : $scope.multiple;
                    $scope.cropable = angular.isUndefined($scope.cropable) ? true : $scope.cropable;
        
                    $scope.maxImgAmount = angular.isUndefined($scope.maxImgAmount) ? 3 : $scope.maxImgAmount;
                    $scope.maxImgSize = angular.isUndefined($scope.maxImgSize) ? 1 : $scope.maxImgSize;
                    $scope.urlRoot = angular.isUndefined($scope.urlRoot) ? 'device' : $scope.urlRoot;
                    $scope.urlType = angular.isUndefined($scope.urlType) ? 'ftp' : $scope.urlType;
                    const imgRootObj = {
                        'ftp': ybConfig.getConfig().baseUrl.BjxlshFtp,
                        'oss': ybConfig.getConfig().baseUrl.ImgOssUrl,
                        'minio': ybConfig.getConfig().baseUrl.ImgMinioUrl + $scope.mnDir,
                    }
                    const imgUploadUrlObj = {
                        'ftp': '/ftp/uploadImg',
                        'oss': '/obs/uploadImg',
                        'minio': '/minio/uploadImage',
                    }
        
                    $scope.handleFileSelect = function (files) {
                        // 判断图片格式 和 大小
                        var errMsgStr = "";
                        angular.forEach(files, function (item, index) {
                            if (!item.type.startsWith('image/')) {
                                errMsgStr += item.name + " 格式不正确；<br/>";
                                item.isValidateError = true;
                            } else if (item.size > $scope.maxImgSize * 1204 * 1024) {
                                errMsgStr += item.name + " 尺寸超过" + $scope.maxImgSize + "M；<br/>";
                                item.isValidateError = true;
                            }
                        })
                        if (!!errMsgStr) {
                            files = files.filter(function (item) { return !item.isValidateError });
                            ybWidget.ShowMessage(errMsgStr, MESG_TYPE.Error, { isHtml: true, isNotCenter: true })
                        }
            
                        var exceedNum = $scope.dataModel.length + files.length - $scope.maxImgAmount;
                        if (exceedNum > 0) {
                            // 超过最大上传数量
                            files.splice(-exceedNum, exceedNum);
                        }
            
                        angular.forEach(files, function (item) {
                            (function (file) {
                                var reader = new FileReader();
                                reader.onload = function (evt) {
                                    $scope.$apply(function ($scope) {
                                        $scope.dataModel.push({
                                            img: file,
                                            base64: evt.target.result
                                        });
                                    });
                                }
                                reader.readAsDataURL(file);
                            })(item)
                        })
                    };
        
                    $scope.delFile = function (index) {
                        $scope.dataModel.splice(index, 1);
                    };
        
                    $scope.scissorFile = function (index) {
                        ybWidget.ScissorPicture({ curIdx: index, curFile: $scope.dataModel[index] }).then(function (data) {
                            data.curFile.hasUpload = false; // 该张图片需要再次上传
                            $scope.dataModel.splice(data.curIdx, 1, data.curFile);
                        })
                    };
        
                    const uploadUrl = ybHttp.RequestUrl($scope.urlRoot, imgUploadUrlObj[$scope.urlType]);
                    
                    var uploadFlag; // 图片批量上传正在进行中标志
                    var uploadTimeInterval = 1000; // 上传接口的时间间隔
                    $scope.uploadFile = function () {
                        if (uploadFlag) return;
                        uploadFlag = true
                        var uploadFileList = $scope.dataModel.filter(function (item) { return !item.hasUpload && (item.cropImg || item.img) }); // 需要上传的文件列表
                        setTimeout(function () {
                            uploadFlag = false;
                        }, uploadFileList.length * uploadTimeInterval);
            
                        angular.forEach(uploadFileList, function (file, index) {
                            setTimeout(function () {
                                Upload.upload({
                                    url: uploadUrl,
                                    data: { imgFile: file.cropImg || file.img }
                                }).then(function (resp) {
                                    var resData = resp.data;
                                    if (resData.code !== 0) {
                                        ybWidget.ShowMessage(resData, MESG_TYPE.Error);
                                    } else {
                                        const resDataValue = resData.value;
                                        file.imgUrl = resDataValue.imageUrl || resDataValue.key || resDataValue;
                                        file.imgUrlShow = imgRootObj[$scope.urlType] + file.imgUrl;
                                        file.hasUpload = true; // 该张图片已经上传过
                                    }
                                })
                            }, 0) // 图片上传接口 支持快速调用，取消上传时的时间间隔：uploadTimeInterval*index，改为0
                        })
                    };
        
                    $scope.isUploadDisabled = function () {
                        return $scope.dataModel.length == 0 || $scope.dataModel.every(function (item) { return item.hasUpload })
                    };
        
                    $scope.viewImage = function (item) {
                        ybWidget.ViewImage({
                            FileUrl: item
                        })
                    };
                }
            }
        }])
        // 高德地图
        .directive('gaodeMap', ['$q', function ($q) {
            return {
                restrict: 'E',
                replace: true,
                templateUrl: "js/directive/tpl/gaodeMap.html",
                scope: {
                    options: '=',
                    onlyShowRoute: '=?', // 是否为近展示路线模式
                    onSelect: '&'
                },
                link: function ($scope) {
                    // 如需使用，先引入高德地图插件
                    // <script src="https://webapi.amap.com/maps?v=1.4.15&key=1f17420841b844e8e03d4ff72574e1ef&plugin=AMap.Geocoder&plugin=AMap.PlaceSearch&plugin=AMap.DistrictSearch&plugin=AMap.Driving"></script>
                    $scope.addressDetailShow = { value: '' }
                    $scope.matchedPlaces = []
        
                    var map = new AMap.Map("container", {
                        zoom: 17
                    });
        
                    if ($scope.onlyShowRoute) {
                        var driving = new AMap.Driving({
                            map: map,
                            panel: "panel", // 查看路线时会展示路线的详细信息
                            policy: 2 // 距离最短策略
                        })
                        driving.search($scope.options.startLngLatArr, $scope.options.endLngLatArr, function () {
                            console.log('路线绘制完成')
                        })
                    }
        
                    // 覆盖物(点标记)
                    var marker = new AMap.Marker()
        
                    // 地理编码与逆地理编码类，用于地址描述与坐标(经纬度)之间的转换-----------插件
                    var geocoder = new AMap.Geocoder({
                        extensions: 'all'
                    })
        
                    // 输入提示插件--------------------------------------------------------插件
                    var placeSeharch = new AMap.PlaceSearch({
                        extensions: 'all',
                        pageSize: 20,
                        pageIndex: 1
                    })
        
                    $scope.$watch("options", function (newValue) {
                        if (newValue && newValue.lng && newValue.lat && newValue.address) {
                            $scope.addressDetailShow.value = newValue.address
                            setSearchCityByLngLat(newValue.lng, newValue.lat, true)
                        } else {
                            // 没有经纬度时默认取所在城市的中心
                            const lnglatObj = map.getCenter()
                            setSearchCityByLngLat(lnglatObj.getLng(), lnglatObj.getLat())
                        }
                    }, true);
        
                    map.on('click', function (e) {
                        if ($scope.onlyShowRoute) {
                            return
                        }
                        const lnglatObj = e.lnglat || {}
                        setSearchCityByLngLat(lnglatObj.getLng(), lnglatObj.getLat()).then(() => {
                            placeSeharch.searchNearBy('', lnglatObj, 50000, function (status, result) {
                                if (status == 'complete' && result.info === 'OK') {
                                    $scope.$apply(function () {
                                        handelSearchData(result.poiList.pois)
                                    })
                                }
                            })
                        })
                    });
        
                    // 通过经纬度 设置搜索时所在的市
                    function setSearchCityByLngLat(lng, lat, isEdit) {
                        var defer = $q.defer();
            
                        geocoder.getAddress([lng, lat], (status, result) => {
                            if (status === 'complete' && result.info === 'OK') {
                                if (result.regeocode) {
                                    const { province, city } = result.regeocode.addressComponent
                                    placeSeharch.setCity(city || province) // 设置搜索时所在的市
                                    map.setCenter([lng, lat]) // 设置地图的中心
                
                                    if (isEdit) {
                                        marker.setMap(map)
                                        marker.setPosition([lng, lat]) // 设置点标记的位置
                    
                                        const divisionArr = [province, city]
                                        const positionArr = [lng, lat]
                                        $scope.onSelect()($scope.addressDetailShow.value, divisionArr, positionArr)
                                    }
                
                                    defer.resolve();
                                }
                            }
                        })
                        return defer.promise;
                    }
        
                    // 通过给定位置地址描述 查询 兴趣点列表（想查询的 相关联的位置列表）
                    $scope.searchPlace = function () {
                        if (!$scope.addressDetailShow.value) {
                            $scope.matchedPlaces.length = 0
                            return
                        }
                        placeSeharch.search($scope.addressDetailShow.value, (status, result) => {
                            if (status == 'complete' && result.info === 'OK') {
                                $scope.$apply(function () {
                                    handelSearchData(result.poiList.pois)
                                })
                            }
                        })
                    }
        
                    function handelSearchData(data) {
                        $scope.matchedPlaces = data.filter(p => p.address).map(pp => {
                            const { name, pname, cityname, adname, address, location } = pp
                            const citynameT = cityname == pname ? '' : cityname
                            return {
                                name: name,
                                pname: pname,
                                citynameT: citynameT,
                                adname: adname,
                                addressDetail: pname + citynameT + adname + address,
                                location: location
                            }
                        })
                    }
        
                    // 点击指定兴趣点
                    $scope.handleSelectAddress = function (obj, idx) {
                        $scope.curSelIdx = idx
            
                        const { pname, citynameT, adname, addressDetail, location: lnglatObj } = obj
            
                        $scope.addressDetailShow.value = addressDetail
            
                        const lng = lnglatObj.getLng()
                        const lat = lnglatObj.getLat()
            
                        placeSeharch.setCity(citynameT || pname) // 设置搜索时所在的市
                        map.setCenter([lng, lat]) // 设置地图的中心
                        marker.setMap(map)
                        marker.setPosition([lng, lat]) // 设置点标记的位置
            
                        const divisionArr = [pname, citynameT, adname]
                        const positionArr = [lng, lat]
                        $scope.onSelect()(addressDetail, divisionArr, positionArr)
                    }
        
                }
            }
        }])
        ;
})(window, window.angular);
